package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
	//	_ "github.com/mattn/go-sqlite3"
)

// Simple Gtk3 Application written in go.
// This application creates a window on the application callback activate.
// More GtkApplication info can be found here -> https://wiki.gnome.org/HowDoI/GtkApplication

func main() {
	// Create Gtk Application, change appID to your application domain name reversed.
	const appID = "org.gtk.example"
	application, err := gtk.ApplicationNew(appID, glib.APPLICATION_FLAGS_NONE)
	// Check to make sure no errors when creating Gtk Application
	checkErr(err)
	// Application signals available
	// startup -> sets up the application when it first starts
	// activate -> shows the default first window of the application (like a new document). This corresponds to the application being launched by the desktop environment.
	// open -> opens files and shows them in a new window. This corresponds to someone trying to open a document (or documents) using the application from the file browser, or similar.
	// shutdown ->  performs shutdown tasks
	// Setup Gtk Application callback signals
	application.Connect("startup", func() {
		log.Println("application startup")
	})
	application.Connect("activate", func() {
		log.Println("application activate")
		onActivate(application)
	})
	application.Connect("shutdown", func() {
		log.Println("application shutdown")
	})
	// Run Gtk application
	os.Exit(application.Run(os.Args))
}

// Callback signal from Gtk Application
func onActivate(application *gtk.Application) * gtk.Window {

	var appwin * gtk.Window
	var sqlactgroup *glib.SimpleActionGroup

	appwin, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	checkErr(err)

	// Create a new grid widget to arrange child widgets
	grid, err := gtk.GridNew()
	// gtk.Grid embeds an Orientable struct to simulate the GtkOrientable	// GInterface.  Set the orientation from the default horizontal to	// vertical.
	grid.SetOrientation(gtk.ORIENTATION_VERTICAL)

	// Create some widgets to put in the grid.
	lab, err := gtk.LabelNew("Just a label")
	btn, err := gtk.ButtonNewWithLabel("Button with label")
	entry, err := gtk.EntryNew()
	spnBtn, err := gtk.SpinButtonNewWithRange(0.0, 1.0, 0.001)
	nb, err := gtk.NotebookNew()


	// Calling (*gtk.Container).Add() with a gtk.Grid will add widgets next
	// to each other, in the order they were added, to the right side of the
	// last added widget when the grid is in a horizontal orientation, and
	// at the bottom of the last added widget if the grid is in a vertial
	// orientation.  Using a grid in this manner works similar to a gtk.Box,
	// but unlike gtk.Box, a gtk.Grid will respect its child widget's expand
	// and margin properties.
	grid.Add(btn)
	grid.Add(lab)
	grid.Add(entry)
	grid.Add(spnBtn)

	// Widgets may also be added by calling (*gtk.Grid).Attach() to specify
	// where to place the widget in the grid, and optionally how many rows
	// and columns to span over.
	//
	// Additional rows and columns are automatically added to the grid as
	// necessary when new widgets are added with (*gtk.Container).Add(), or,
	// as shown in this case, using (*gtk.Grid).Attach().
	//
	// In this case, a notebook is added beside the widgets inserted above.
	// The notebook widget is inserted with a left position of 1, a top
	// position of 1 (starting at the same vertical position as the button),
	// a width of 1 column, and a height of 2 rows (spanning down to the
	// same vertical position as the entry).
	//
	// This example also demonstrates how not every area of the grid must
	// contain a widget.  In particular, the area to the right of the label
	// and the right of spin button have contain no widgets.
	grid.Attach(nb, 1, 1, 1, 2)
	nb.SetHExpand(true)
	nb.SetVExpand(true)

	// Add a child widget and tab label to the notebook so it renders.
	nbChild, err := gtk.LabelNew("Notebook content")
	nbTab, err := gtk.LabelNew("Tab label")
	nb.AppendPage(nbChild, nbTab)
	entry.Connect("activate", func() {
		s, _ := entry.GetText()
		nbChild.SetText(s)
	})
	pb, err := gtk.ProgressBarNew()
	pb.SetMarginBottom(10)
	grid.AttachNextTo(pb, spnBtn, gtk.POS_BOTTOM, 1, 1)

	// Pass in a ProgressBar and the target SpinButton as user data rather
	// than using the sb and pb variables scoped to the anonymous func.
	// This can be useful when passing in a closure that has already been
	// generated, but when you still wish to connect the callback with some
	// variables only visible in this scope.
	spnBtn.Connect("value-changed", func(spnBtn *gtk.SpinButton, pb *gtk.ProgressBar) {
		pb.SetFraction(spnBtn.GetValue() / 1)
	}, pb)
	label, err := gtk.LabelNew("")
	s := "Hyperlink to <a href=\"https://www.cyphertite.com/\">Cyphertite</a> for your clicking pleasure"
	label.SetMarkup(s)
	grid.AttachNextTo(label, spnBtn, gtk.POS_BOTTOM, 2, 1)

	// Some GTK callback functions require arguments, such as the
	// 'gchar *uri' argument of GtkLabel's "activate-link" signal.
	// These can be used by using the equivalent go type (in this case,
	// a string) as a closure argument.
	label.Connect("activate-link", func(_ *gtk.Label, uri string) {
		fmt.Println("you clicked a link to:", uri)
	})

	// Add the grid to the window, and show all widgets.
	appwin.Add(grid)
/*	//
	lbl, err := gtk.LabelNew("测试 topic")
	appwin.Add(lbl)
	lbl.SetText("改写lbl txt")

	var button * gtk.Button
    button, err =gtk.ButtonNew()
	button.SetLabel("sqlite 测试")
    button.SetTooltipText("sqlite 测试")
    appwin.Add(button)
*/
	sqlactgroup = glib.SimpleActionGroupNew()
    sa_open :=glib.SimpleActionNew("open",nil)
    sa_open.Connect("activate",func(){
    	//如果数据库不存在，则创建 sqlite3 数据库 ‘myerrortopic.db’
		fmt.Println("打开一个数据库")
	})
	sqlactgroup.AddAction(sa_open)

	appwin.SetTitle("Basic Application.")
	appwin.SetDefaultSize(800, 600)
	appwin.SetPosition(gtk.WIN_POS_CENTER)
	appwin.ShowAll()
	application.AddWindow(appwin)
	return appwin
}
//GtkApplicationWindow as a GtkBin subclass ,a GtkApplicationWindow can only contain one widget at a time
func test()  {
	//打开数据库，如果不存在，则创建
	db, err := sql.Open("sqlite3", "./foo.db")
	checkErr(err)

	//创建表
	sql_table := `
    CREATE TABLE IF NOT EXISTS userinfo(
        uid INTEGER PRIMARY KEY AUTOINCREMENT,
        username VARCHAR(64) NULL,
        departname VARCHAR(64) NULL,
        created DATE NULL
    );
    `

	db.Exec(sql_table)

	// insert
	stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, created) values(?,?,?)")
	checkErr(err)

	res, err := stmt.Exec("wangshubo", "国务院", "2017-04-21")
	checkErr(err)

	id, err := res.LastInsertId()
	checkErr(err)

	fmt.Println(id)

	// update
	stmt, err = db.Prepare("update userinfo set username=? where uid=?")
	checkErr(err)

	res, err = stmt.Exec("wangshubo_new", id)
	checkErr(err)

	affect, err := res.RowsAffected()
	checkErr(err)

	fmt.Println(affect)

	// query
	rows, err := db.Query("SELECT * FROM userinfo")
	checkErr(err)
	var uid int
	var username string
	var department string
	var created time.Time

	for rows.Next() {
		err = rows.Scan(&uid, &username, &department, &created)
		checkErr(err)
		fmt.Println(uid)
		fmt.Println(username)
		fmt.Println(department)
		fmt.Println(created)
	}

	rows.Close()

	// delete
	stmt, err = db.Prepare("delete from userinfo where uid=?")
	checkErr(err)

	res, err = stmt.Exec(id)
	checkErr(err)

	affect, err = res.RowsAffected()
	checkErr(err)

	fmt.Println(affect)

	db.Close()


}

func checkErr(err error) {
	if err != nil {
		//panic(err)
		log.Fatal(err)

	}
}